package org.fastsyncer.connector.ldap;

import java.util.HashMap;
import java.util.List;

import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;

import org.apache.commons.lang.StringUtils;
import org.fastsyncer.common.constant.ConnectorConstant;
import org.fastsyncer.common.entity.BaseInfo;
import org.fastsyncer.common.entity.LdapConfig;
import org.fastsyncer.connector.util.LdapUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ldap.NamingException;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.filter.Filter;
import org.springframework.ldap.filter.GreaterThanOrEqualsFilter;
import org.springframework.ldap.filter.LessThanOrEqualsFilter;
import org.springframework.ldap.filter.NotFilter;
import org.springframework.ldap.filter.OrFilter;

public class LdapConnector implements Ldap {

	private final Logger LOG = LoggerFactory.getLogger(LdapConnector.class);
	
	private static LdapConnector instance = null;

	public LdapConnector() {
	}

	public static LdapConnector getInstance() {
		if (instance == null) {
			synchronized (LdapConnector.class) {
				instance = new LdapConnector();
			}
		}
		return instance;
	}

	/**
	 * 判断URL是否可用
	 * 
	 * @Title: isAlive
	 * @Description: 判断URL是否可用
	 * @param config
	 *            Ldap配置
	 * @return: boolean true: 可用 false: 不可用
	 */
	public boolean isAlive(LdapConfig config){
		try {
			LdapTemplate ldapTemplate = getLdapTemplate(config);
			if(ldapTemplate!=null){
				return true;
			}
		} catch (Exception e) {
			LOG.error("unable to connect:" + config.getUrl(), e.getMessage());
		}
		return false;
	}
	
	@Override
	public LdapTemplate getLdapTemplate(LdapConfig config) {
		return LdapUtil.getLdapTemplate(config);
	}

	@Override
	public BaseInfo getBaseInfoConnector(LdapConfig config) {
		LdapTemplate ldapTemplate = LdapUtil.getLdapTemplate(config);

		// 且
		AndFilter filter = new AndFilter();
		filter.and(new EqualsFilter("objectclass", "person"));

		BaseInfo connector = LdapUtil.getDataSourceConnector(ldapTemplate, filter.encode());
		return connector;
	}

	private int count = 0;

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public int getRowCount(LdapTemplate ldapTemplate, String filter) throws javax.naming.NamingException {
		// 转换器
		AttributesMapper mapper = new AttributesMapper() {
			public Object mapFromAttributes(Attributes attrs) throws NamingException, javax.naming.NamingException {
				count++;
				return null;
			}
		};

		SearchControls controls = new SearchControls();
		controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
		// 查询返回的字段
		controls.setReturningAttributes(new String[] { "objectclass" });
		ldapTemplate.search("", filter, controls, mapper);
		return count;
	}

	/**
	 * @Title: getFilter 
	 * @Description: 获取查询条件
	 * @param extendObjects 继承对象
	 * @param query 过滤的字段，包括and/or条件
	 * @return: String
	 */
	public String getFilter(List<String> extendObjects, HashMap<String, List<HashMap<String, String>>> query) {
		// 解析继承对象
		AndFilter filter = new AndFilter();
		for (String obj : extendObjects) {
			filter.and(new EqualsFilter("objectclass", obj));
		}
		
		// 解析同步的属性
		OrFilter orFilter = new OrFilter();
		if (query != null && !query.isEmpty()) {
			// 拼接并且
			List<HashMap<String, String>> addList = query.get(ConnectorConstant.OPERTION_QUERY_AND);
			this.getOperFilter(ConnectorConstant.OPERTION_QUERY_AND, orFilter, addList);

			// 拼接或者
			List<HashMap<String, String>> orList = query.get(ConnectorConstant.OPERTION_QUERY_OR);
			this.getOperFilter(ConnectorConstant.OPERTION_QUERY_OR, orFilter, orList);
		}
		
		// 添加过滤属性
		String f = orFilter.encode();
		if(!StringUtils.isBlank(f)){
			filter.and(orFilter);
		}
		
		String c = filter.encode();
		return StringUtils.isBlank(c) ? "(objectclass=*)" : c;
	}

	private void getOperFilter(String operator, OrFilter filter, List<HashMap<String, String>> list) {
		if (list == null || list.isEmpty()) {
			return;
		}
		int size = list.size();
		switch (operator) {
		case ConnectorConstant.OPERTION_QUERY_AND:
			AndFilter filterAdd = new AndFilter();
			for (int i = 0; i < size; i++) {
				HashMap<String, String> c = list.get(i);
				String name = c.get("name");
				String oper = c.get("operator");
				String value = c.get("value");
				// 获取查询条件
				Filter f = this.getFilterByOpr(oper, name, value);
				filterAdd.and(f);
			}
			filter.or(filterAdd);
			break;
		case ConnectorConstant.OPERTION_QUERY_OR:
			OrFilter filterOr = new OrFilter();
			for (int i = 0; i < size; i++) {
				HashMap<String, String> c = list.get(i);
				String name = c.get("name");
				String oper = c.get("operator");
				String value = c.get("value");
				// 获取查询条件
				Filter f = this.getFilterByOpr(oper, name, value);
				filterOr.or(f);
			}
			filter.or(filterOr);
			break;
		default:
			break;
		}
	}

	private Filter getFilterByOpr(String oper, String name, String value) {
		Filter f = null;
		switch (oper) {
		case "equal":
			f = new EqualsFilter(name, value);
			break;
		case "notEqual":
			f = new NotFilter(new EqualsFilter(name, value));
			break;
		case "gtAndEqual":
			f = new GreaterThanOrEqualsFilter(name, value);
			break;
		case "ltAndEqual":
			f = new LessThanOrEqualsFilter(name, value);
			break;
		default:
			// 默认相等
			f = new EqualsFilter(name, value);
			break;
		}
		return f;
	}

}
